A well-designed REST API is the backbone of modern web applications. This article covers proven best practices that make APIs intuitive, consistent, and developer-friendly.

1. URL Design

# ✅ Good REST URL design
GET    /api/v1/users          # List all users
GET    /api/v1/users/123      # Get specific user
POST   /api/v1/users          # Create a user
PUT    /api/v1/users/123      # Update a user
DELETE /api/v1/users/123      # Delete a user

# ✅ Nested resources
GET    /api/v1/users/123/posts        # User's posts
GET    /api/v1/users/123/posts/456    # Specific post

# ❌ Avoid
GET    /api/v1/getUsers
POST   /api/v1/createUser
GET    /api/v1/user-list
✅ Rules of Thumb

Use plural nouns for resources (/users not /user). Use hyphens for multi-word resources (/blog-posts). Never use verbs in URLs — HTTP methods express the action.

2. HTTP Methods

  • GET: Read (safe, idempotent)
  • POST: Create (not idempotent)
  • PUT: Full update (idempotent)
  • PATCH: Partial update (idempotent)
  • DELETE: Remove (idempotent)

3. Error Handling

// Consistent error response format
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Invalid input data",
    "details": [
      {"field": "email", "message": "Must be a valid email address"},
      {"field": "age", "message": "Must be 18 or older"}
    ]
  }
}

// Status codes
// 200 OK, 201 Created, 204 No Content
// 400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found
// 422 Unprocessable Entity, 429 Too Many Requests
// 500 Internal Server Error
Ad

4. Authentication

// JWT Authentication example
// Request
fetch('/api/v1/users', {
  headers: {
    'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIs...',
    'Content-Type': 'application/json'
  }
});

// Server-side middleware
function authenticate(req, res, next) {
  const token = req.headers.authorization?.split(' ')[1];
  if (!token) return res.status(401).json({ error: 'Token required' });
  
  try {
    const decoded = jwt.verify(token, process.env.JWT_SECRET);
    req.user = decoded;
    next();
  } catch (e) {
    res.status(401).json({ error: 'Invalid token' });
  }
}

5. Pagination & Filtering

# Cursor-based pagination (recommended)
GET /api/v1/posts?cursor=abc123&limit=20

# Offset-based pagination
GET /api/v1/posts?page=2&per_page=20

# Filtering & sorting
GET /api/v1/posts?category=tech&sort=-created_at&status=published
// Pagination response format
{
  "data": [...],
  "pagination": {
    "total": 150,
    "page": 2,
    "per_page": 20,
    "next_cursor": "def456",
    "has_more": true
  }
}

6. Versioning

  • URL versioning (recommended): /api/v1/users, /api/v2/users
  • Header versioning: Accept: application/vnd.api+json;version=2
  • Query parameter: /api/users?version=2 (least recommended)

Well-designed REST APIs improve developer productivity, reduce bugs, and make systems easier to maintain. Apply these patterns consistently across your projects.